package cn.hy.face.common.service;

import cn.hy.face.common.constant.ProjectConstant;
import cn.hy.face.common.entity.FaceRecognition;
import cn.hy.face.common.entity.FaceRecognitionExample;
import cn.hy.face.common.enums.DataStatusEnum;
import cn.hy.face.common.enums.FaceStatusEnum;
import cn.hy.face.common.mapper.FaceRecognitionMapper;
import cn.hy.face.common.utils.IdUtils;
import cn.hy.face.common.utils.UserUtils;
import cn.hy.face.common.vo.*;
import cn.hy.face.common.vo.UsersQueryVO;
import cn.hy.face.module.sync.utils.SyncUtils;
import cn.hy.face.mqtt.MqttGateway;
import cn.hy.face.thrift.ThriftService;
import cn.hy.face.thrift.dto.reponese.SysOfficeDTO;
import cn.hy.face.thrift.dto.reponese.SysUserDTO;
import cn.hy.face.thrift.dto.request.OfficeQueryDTO;
import cn.hy.face.utils.PageUtils;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.thrift.TException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: face
 * @author: qingxiangen
 * @create: 2019-09-04 11:27
 * @description: 人脸识别服务
 **/
@Service
public class FaceRecognitionService extends BaseService {
    /**
     * mapper
     */
    @Autowired
    private FaceRecognitionMapper faceRecognitionMapper;
    /**
     * pms服务
     */
    @Autowired
    private ThriftService thriftService;
    /**
     * mqtt服务
     */
    @Autowired
    private MqttGateway mqttGateway;

    /**
     * 根据学校id获取所有年级及班级信息
     * @param schoolId
     */
    public List<BusiGradeVO> getOfficeList(String schoolId) throws Exception {
        List<SysOfficeDTO> offices = this.getClassList(schoolId, null, 1);
        Map<String, List<SysOfficeDTO>> userGroupMap = offices.stream().collect(Collectors.groupingBy(a -> String.valueOf(a.getBusiClass().getGrade())));
        List<BusiGradeVO> gradeList = new ArrayList<>();
        for (Map.Entry<String, List<SysOfficeDTO>> entry : userGroupMap.entrySet()) {
            BusiGradeVO busiGradeVO = new BusiGradeVO();
            List<SysOfficeDTO> officeList = entry.getValue();
            busiGradeVO.setGrade(entry.getKey() == null ? 0 : Integer.valueOf(entry.getKey()));
            if(CollectionUtils.isEmpty(officeList)){
                continue;
            }

            busiGradeVO.setOfficeName(officeList.get(0).getBusiClass().getGradeName());
            List<BusiClassVO> classList = officeList.stream().map(a -> new BusiClassVO(a.getBusiClass().getOfficeId(), StringUtils.isEmpty(a.getBusiClass().getClassCode()) ? 0 : Integer.valueOf(a.getBusiClass().getClassCode()), a.getBusiClass().getClassName())).distinct().collect(Collectors.toList());//已去重
            classList.sort((BusiClassVO boBre, BusiClassVO boAft) -> Integer.valueOf(boBre.getClassCode()) - Integer.valueOf((boAft.getClassCode())));
            busiGradeVO.setChildren(classList);
            gradeList.add(busiGradeVO);
        }
        gradeList.sort((BusiGradeVO bgBre, BusiGradeVO bgAft) -> bgAft.getGrade() - bgBre.getGrade());
        return gradeList;
    }

    /**
     * 根据年级id获取所有班级
     * @param schoolId
     */
    private List<SysOfficeDTO> getClassList(String schoolId, String classId, Integer classDetail) throws Exception {
        OfficeQueryDTO queryDTO = new OfficeQueryDTO();
        queryDTO.setOfficeId(classId);
        queryDTO.setClassDetail(classDetail);
        List<SysOfficeDTO> offices = thriftService.findOfficeBySchoolIdAndOtherParams(schoolId,queryDTO);
        return offices;
    }

    /**
     * 根据班级id获取所有学生信息 - 分页查询
     * @param queryVO
     * @return
     * @throws TException
     */
    public PageInfo<SysStudentVO> getUsersByClassId(UsersQueryVO queryVO)  throws TException {
        if(queryVO.getPageNum() == null){
            queryVO.setPageNum(1);
        }
        if(queryVO.getPageSize() == null){
            queryVO.setPageSize(10);
        }
        return getUsersByClassId(queryVO,null);
    }

    /**
     * 根据班级id获取所有学生信息
     * @param preSyncTime
     * @return
     * @throws TException
     */
    private PageInfo<SysStudentVO> getUsersByClassId(UsersQueryVO queryVO, Long preSyncTime)  throws TException {
        if (hasQueryRecord(queryVO.getStatus())){
            return getUsersByClassIdAndFaceStatus(queryVO);
        }
        PageInfo<SysUserDTO> pageInfo = thriftService.findUsersByOfficeId(queryVO.getSchoolId(), queryVO.getClassId(), null, null, queryVO.getRealName());
        List<SysUserDTO> sysUserList = pageInfo.getList();
        if(pageInfo == null || CollectionUtils.isEmpty(sysUserList)){
            return new PageInfo<>();
        }
        List<String> userIds = sysUserList.stream().map(SysUserDTO::getId).collect(Collectors.toList());
        List<FaceRecognition> faces = findFaceRecognitionList(queryVO.getSchoolId(), userIds, null, preSyncTime);
        List<SysStudentVO> studentList = new ArrayList<>();
        for (SysUserDTO sysUser: pageInfo.getList()) {
            FaceRecognition face = null;
            if(queryVO.getStatus() == null){
                face = faces.stream().filter(b -> b.getUserId().equals(sysUser.getId())).findFirst().orElse(null);
            }else{
                face = faces.stream().filter(b -> b.getUserId().equals(sysUser.getId()) && FaceStatusEnum.NO_UPLOAD != FaceStatusEnum.getEnumByCode(b.getFaceStatus())).findFirst().orElse(null);
                if(face != null){
                    continue;
                }
            }
            studentList.add(buildStudent(sysUser, face));
        }
        return  PageUtils.buildPageInfo(studentList, queryVO.getPageNum(), queryVO.getPageSize());
    }

    /**
     * 根据班级id，人脸识别状态获取学生信息
     * @param queryVO
     * @return
     * @throws TException
     */
    private PageInfo<SysStudentVO> getUsersByClassIdAndFaceStatus(UsersQueryVO queryVO)  throws TException {
        List<FaceRecognition> faces = findFaceRecognitionList(queryVO.getSchoolId(), null, queryVO.getStatus(), null);
        if(CollectionUtils.isEmpty(faces)){
            return new PageInfo<>();
        }
        PageInfo<SysUserDTO> pageInfo = thriftService.findUsersByOfficeId(queryVO.getSchoolId(), queryVO.getClassId(), null, null, queryVO.getRealName());
        List<SysUserDTO> sysUserList = pageInfo.getList();
        if(pageInfo == null || CollectionUtils.isEmpty(sysUserList)){
            return new PageInfo<>();
        }
        List<SysStudentVO> studentList = new ArrayList<>();
        for (FaceRecognition face: faces) {
            SysUserDTO sysUser = sysUserList.stream().filter(b -> b.getId().equals(face.getUserId())).findFirst().orElse(null);
            if(sysUser == null){
                continue;
            }
            studentList.add(buildStudent(sysUser, face));
        }
        return PageUtils.buildPageInfo(studentList, queryVO.getPageNum(), queryVO.getPageSize());
    }
    /**
     * 构建学生信息
     * @param sysUser
     * @param face
     * @return
     */
    private SysStudentVO buildStudent(SysUserDTO sysUser, FaceRecognition face){
        SysStudentVO stu = new SysStudentVO();
        stu.setUserId(sysUser.getId());
        stu.setAvatar(sysUser.getAvatar());
        stu.setRealName(sysUser.getRealName());
        if(face != null){
            stu.setId(face.getId());
            stu.setFacePhoto(face.getFacePhoto());
            stu.setFaceStatus(face.getFaceStatus());
            stu.setFailReason(face.getFailReason());
            stu.setStatus(sysUser.getStatus());
            stu.setCreateAt(face.getCreateAt());
            stu.setUpdateAt(face.getUpdateAt());
        }else{
            stu.setId(null);
            stu.setFacePhoto("");
            stu.setFaceStatus(FaceStatusEnum.NO_UPLOAD.getCode());
            stu.setFailReason("");
            stu.setStatus(sysUser.getStatus());
            stu.setCreateAt(null);
            stu.setUpdateAt(null);
        }
        return stu;
    }

    /**
     * 查询人脸状态为成功，失败，校验中的数据
     * @param faceStatus
     * @return
     */
    private boolean hasQueryRecord(Byte faceStatus){
        if (faceStatus != null && faceStatus.byteValue() != FaceStatusEnum.NO_UPLOAD.getCode()){
            return true;
        }
        return false;
    }

    /**
     * 新增或更新人脸识别信息 - 人脸管理调用
     * @param schoolId
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateFacePhoto(String schoolId, String classId, String userId, String facePhoto) throws TException {
        FaceRecognitionExample example = new FaceRecognitionExample();
        example.createCriteria().andSchoolIdEqualTo(schoolId).andUserIdEqualTo(userId).andStatusEqualTo(DataStatusEnum.NORMAL.getCode());
        List<FaceRecognition> faceList = faceRecognitionMapper.selectByExample(example);
        FaceRecognition record = new FaceRecognition();
        record.setSchoolId(schoolId);
        record.setUserId(userId);
        record.setFacePhoto(facePhoto);
        Date now = new Date();
        if(CollectionUtils.isEmpty(faceList)){
            record.setId(IdUtils.newId());
            record.setFaceStatus(FaceStatusEnum.CHECKING.getCode());
            record.setFailReason("");
            record.setCreateAt(now);
            record.setCreateBy(UserUtils.getUserId());
            record.setUpdateAt(now);
            record.setUpdateBy(UserUtils.getUserId());
            record.setStatus(DataStatusEnum.NORMAL.getCode());
            faceRecognitionMapper.insertSelective(record);
        }else{
            record.setUpdateAt(now);
            record.setUpdateBy(UserUtils.getUserId());
            faceRecognitionMapper.updateByExampleSelective(record, example);
        }
        //更新数据后推送消息
        sendFaceData(classId, userId);
    }

    /**
     * 获取所有数据
     * @param schoolId
     * @return
     */
    public List<FaceRecognition> findFaceRecognitionList(String schoolId, List<String> userIds, Byte faceStatus, Long preSyncTime){
        FaceRecognitionExample example = new FaceRecognitionExample();
        FaceRecognitionExample.Criteria criteria = example.createCriteria();
        criteria.andSchoolIdEqualTo(schoolId);
        if(!CollectionUtils.isEmpty(userIds)){
            criteria.andUserIdIn(userIds);
        }
        if(faceStatus != null){
            criteria.andFaceStatusEqualTo(faceStatus);
        }
        if(preSyncTime != null){
            preSyncTime = SyncUtils.formatPreSyncTime(preSyncTime);
            criteria.andUpdateAtGreaterThanOrEqualTo(new Date(preSyncTime));
        }
        return faceRecognitionMapper.selectByExample(example);
    }

    /**
     * 根据班级id获取所有学生信息 - 安卓端调用
     * @param schoolId
     * @param classId
     * @param preSyncTime
     * @return
     * @throws TException
     */
    public List<SysStudentVO> getUsersByClassIdToAndroid(String schoolId, String classId, Long preSyncTime)  throws TException {
        UsersQueryVO queryVO = new UsersQueryVO();
        queryVO.setSchoolId(schoolId);
        queryVO.setClassId(classId);
        PageInfo<SysStudentVO> pageInfo = getUsersByClassId(queryVO, preSyncTime);
        return pageInfo.getList();
    }

    /**
     * 根据学生id获取学生人脸信息 - 安卓端调用
     * @param schoolId
     * @return
     */
    public SysStudentVO findFaceInfoByUserIdToAndroid(String schoolId, String userId) throws TException{
        SysUserDTO sysUser = thriftService.findUserByUserId(userId);
        if(sysUser == null){
            return null;
        }
        FaceRecognitionExample example = new FaceRecognitionExample();
        FaceRecognitionExample.Criteria criteria = example.createCriteria();
        criteria.andSchoolIdEqualTo(schoolId).andUserIdEqualTo(userId);
        List<FaceRecognition> faces = faceRecognitionMapper.selectByExample(example);
        FaceRecognition face = null;
        if(!CollectionUtils.isEmpty(faces)){
            face = faces.get(0);
        }
        return buildStudent(sysUser, face);
    }

    /**
     * 校验人脸识别信息 - 安卓端调用
     * @param schoolId
     * @param userId
     * @param faceStatus
     * @param failReason
     * @param updateAt
     * @throws TException
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateFaceStatusToAndroid(String schoolId, String userId, Byte faceStatus, String failReason, Long updateAt) throws TException {
        //时间为空不更新状态
        if(updateAt == null){
            return;
        }
        FaceRecognition record = new FaceRecognition();
        record.setSchoolId(schoolId);
        record.setUserId(userId);
        if(FaceStatusEnum.CHECK_SUCCESS == FaceStatusEnum.getEnumByCode(faceStatus)){
            record.setFaceStatus(FaceStatusEnum.CHECK_SUCCESS.getCode());
            record.setFailReason("");
        }else{
            record.setFaceStatus(FaceStatusEnum.CHECK_FAIL.getCode());
            record.setFailReason(failReason == null ? "" : failReason);
        }
        FaceRecognitionExample example = new FaceRecognitionExample();
        example.createCriteria().andSchoolIdEqualTo(schoolId).andUserIdEqualTo(userId).andStatusEqualTo(DataStatusEnum.NORMAL.getCode());
        List<FaceRecognition> faceList = faceRecognitionMapper.selectByExample(example);
        if(!CollectionUtils.isEmpty(faceList)){
            FaceRecognition one = faceList.get(0);
            //时间不一致不更新
            if(new Date(updateAt).compareTo(one.getUpdateAt()) != 0){
                return;
            }
            record.setUpdateBy(ProjectConstant.SYSTEM);
            faceRecognitionMapper.updateByExampleSelective(record, example);
            return;
        }
        //新增记录
        Date now = new Date();
        record.setId(IdUtils.newId());
        record.setFaceStatus(FaceStatusEnum.CHECKING.getCode());
        record.setFailReason("");
        record.setCreateAt(now);
        record.setCreateBy(ProjectConstant.SYSTEM);
        record.setUpdateAt(now);
        record.setUpdateBy(ProjectConstant.SYSTEM);
        record.setStatus(DataStatusEnum.NORMAL.getCode());
        faceRecognitionMapper.insertSelective(record);
    }

    /**
     * 更新人脸照片后推送安卓端消息
     * @param classId
     * @param userId
     */
    private void sendFaceData(String classId, String userId){
        logger.info("【人脸识别管理】 更新人脸照片后推送安卓端消息classId={},userId={}", classId, userId);
        if(StringUtils.isEmpty(classId) || StringUtils.isEmpty(userId)){
            return;
        }
        Map map = new HashMap();
        map.put(ProjectConstant.MQTT_USER_FACE, userId);
        mqttGateway.sendToMqtt(ProjectConstant.TOPIC + classId, JSON.toJSONString(map));
    }
}
